package GameLogic

import (
	"PBMessage"
	"container/list"
	"fmt"

	"git.oschina.net/yangdao/extlib/log"
	"git.oschina.net/yangdao/extlib/math3d"

	"git.oschina.net/yangdao/GameLib/Unit"
	"git.oschina.net/yangdao/SGLisp/parse"
	"git.oschina.net/yangdao/extlib/data_type"
	. "git.oschina.net/yangdao/extlib/math3d"

	"github.com/golang/protobuf/proto"
)

const (
	gameUnitStateSelectUnit = iota
	gameUnitStateSelectIdle
)

//GameUnit 游戏单位
type GameUnit struct {
	*Unit.Unit
	scenePlayer  *ScenePlayer
	UnitID       int
	curState     IState
	curStateName string
	states       map[string]IState
	commonds     *list.List

	isMoveing bool
	targetPos *Vec3
	Speed     int

	preMovePos    math3d.Vec3
	startMoveTime int64

	hitMover *Unit.LineMover

	addStamina int
}

//Init 初始化
func (this *GameUnit) Init(guid int64, needState bool, scene Unit.IUnitScene) {
	this.commonds = list.New()
	this.isMoveing = false
	this.targetPos = &math3d.Vec3{}
	this.Unit = &Unit.Unit{GUID: guid, Scene: scene}
	if needState {
		this.states = map[string]IState{
			"selectUnit":    &selectUnitState{genericState: &genericState{gameUnit: this}},
			"idle":          &idleState{genericState: &genericState{gameUnit: this}},
			"run":           &runState{genericState: &genericState{gameUnit: this}},
			"canRunAbility": &canRunAbilityState{genericState: &genericState{gameUnit: this}},
			"hitFly":        &hitFlyState{genericState: &genericState{gameUnit: this}},
			"die":           &dieState{genericState: &genericState{gameUnit: this}},
		}
		this.chageState("selectUnit")
	}
	this.hitMover = &Unit.LineMover{Mover: &Unit.Mover{Name: "LineMover"}}
	this.hitMover.Unit = this.Unit

}
func (this *GameUnit) Base() *Unit.Unit {
	return this.Unit
}

func (this *GameUnit) Load() {
	this.Unit.LoadUnitByConfig( Unit.LispTables.UnitTable.Get(this.UnitID).(data_type.IAssociative), this.Scene)
	this.Unit.Context.Define("Unit.Pos", &parse.ObjectNode{Val: this.Unit.PosPtr()})
	this.Unit.Context.Define("Unit.Dir", &parse.ObjectNode{Val: &this.Unit.Dir})
	this.AddMover(this.hitMover)
	this.Speed = this.GetProperty(":MoveSpeed").(int)
}

//PushCommond 压入命令
func (g *GameUnit) PushCommond(cmd int, args ...interface{}) {
	tuple := make([]interface{}, len(args)+1)
	tuple[0] = cmd
	for i := 0; i < len(args); i++ {
		tuple[i+1] = args[i]
	}
	g.commonds.PushBack(tuple)
}

func (g *GameUnit) getCommond() (int, []interface{}) {
	if g.commonds.Len() == 0 {
		return -1, nil
	}
	cmd := g.commonds.Front().Value.([]interface{})
	g.commonds.Remove(g.commonds.Front())
	return cmd[0].(int), cmd
}

func (this *GameUnit) onUpdate(dt int) {
	if this.curState != nil {
		this.curState.onUpdate(dt)
	}
	if this.Unit != nil {
		this.Unit.Update(dt)
        if this.Unit.IsLoad {
		this.addStamina += dt
		if this.addStamina > 500 {
			this.addStamina = 0
			oldV := this.GetProperty(":Stamina").(float64)
			max := this.GetProperty(":MaxStamina").(float64)
			newV := oldV + 1.0
			if newV > max {
				newV = max
			}
			if newV != oldV {
				this.SetProperty(":Stamina", newV)
			}
		}
	} 
	}
}

func (g *GameUnit) chageState(newStateName string, args ...interface{}) {
	newState := g.states[newStateName]
	if newState == nil {
		log.Log("GameLogic", "不存在的State"+newStateName, g.Name, g.states)
		return
	}
	if newState != g.curState {
		if g.curState != nil {
			g.curState.onExit()
		}
		g.curState = newState
		g.curStateName = newStateName
		g.curState.onEnter(args...)
	}
}

func (g *GameUnit) toSCCreateUnit() *PBMessage.SC_CreateUnit {
	scCreateUnit := &PBMessage.SC_CreateUnit{}
	if g.scenePlayer != nil {
		scCreateUnit.NickName = proto.String(g.scenePlayer.player.NickName)
	} else {
		scCreateUnit.NickName = proto.String("-")
	}
	scCreateUnit.PlayerId = proto.Int64(g.Unit.GUID)
	scCreateUnit.UnitId = proto.Int32(int32(g.UnitID))
	scCreateUnit.PosX = proto.Int32(int32(g.Unit.Pos().X * 100.0))
	scCreateUnit.PosY = proto.Int32(int32(g.Unit.Pos().Z * 100.0))
	scCreateUnit.TX = proto.Int32(int32(g.targetPos.X))
	scCreateUnit.TY = proto.Int32(int32(g.targetPos.Z))
	return scCreateUnit
}

func (this *GameUnit) toSCMove(nowTime int64, speed int, dir *Vec3) *PBMessage.SC_MoveUnit {
	scMove := &PBMessage.SC_MoveUnit{}
	scMove.Time = proto.Int64(nowTime)
	scMove.PosX = proto.Int32(int32(this.PosPtr().X * 100))
	scMove.PosY = proto.Int32(int32(this.PosPtr().Z * 100))
	scMove.DX = proto.Int32(int32(dir.X * 100))
	scMove.DY = proto.Int32(int32(dir.Z * 100))
	scMove.Time = proto.Int64(nowTime)
	scMove.State = proto.Int32(-1)
	scMove.Speed = proto.Int32(int32(speed))
	scMove.UnitId = proto.Int64(this.GUID)
	return scMove
}

func (this *GameUnit) setPos(prePos *Vec3, nowTime, startTime int64, nowSpeed int) {
	moveSpeed := nowSpeed //this.Unit.GetProperty(":MoveSpeed").(int)
	//fmt.Println(moveSpeed)
	moveTime := int(nowTime - startTime)
	moveNumber := moveSpeed * moveTime
	move := this.Unit.Dir.Scaled(float64(moveNumber) / 1000.0)
	this.Unit.SetPos(*prePos.AddTo(move))
	if this.Unit.Pos().X > 10000 {
		fmt.Println("cnm??", nowTime, startTime)
		panic("cnm???")
	}
}
